#ifndef _ORDER_BASE_NODE_HPP
#define _ORDER_BASE_NODE_HPP 1

#include <time.h>

#include "../constants.hpp"

#include "../BaseNode.hpp"

#include "OrderWorkQueue.hpp"

#include "statemanagement/CheckPointState.hpp"
#include "statemanagement/Certificate.hpp"
#include "statemanagement/ViewChangeRow.hpp"
#include "statemanagement/ViewInfo.hpp"

#include "../messages/ClientRequest.hpp"
#include "../messages/LastExecuted.hpp"
#include "../messages/CPLoaded.hpp"
#include "../messages/CPTokenMessage.hpp"
#include "../messages/RequestCore.hpp"
#include "../messages/Quorum.hpp"
#include "../messages/Retransmit.hpp"
#include "../messages/RequestCP.hpp"
#include "../messages/ReleaseCP.hpp"
#include "../messages/LoadCPMessage.hpp"

#include "../order/messages/MissingCP.hpp"
#include "../order/messages/RelayCP.hpp"
#include "../order/messages/ViewChange.hpp"
#include "../order/messages/NewView.hpp"
#include "../order/messages/ViewChangeAck.hpp"
#include "../order/messages/ConfirmView.hpp"
#include "../order/messages/MissingOps.hpp"
#include "../order/messages/MissingViewChange.hpp"
#include "../order/messages/StartView.hpp"

//#include "../network/concurrentNet/ConcurrentNetwork.hpp"
#include "../network/concurrentNet/TCPNetwork.hpp"

#include "Cleaner.hpp"

namespace BFT
{
  namespace order
  {
    class OrderBaseNode //does NOT inherit from BaseNode, owns a BaseNode instance instead.
    {
    public:
			
      OrderBaseNode(std::string _membership, int _myId); //the second parameter of the cosntructor in the 
      //java implementation is unused
			
      //static OrderBaseNode obn; //TODO needed???
			
      /*
	Handle a byte array, conver the byte array to the appropriate
	message and call the requisite process method
      */
      void handle(boost::shared_ptr<char> _bytes, int _bytes_size);
			
      void handle(boost::shared_ptr<messages::PrePrepare> _pp);
			
      void handle(boost::shared_ptr<std::vector<boost::shared_ptr<BFT::messages::RequestCore> > > _rcs);
			
      uint32_t getCurrentSequenceNumber(); //inlined
			
      bool canCreateBatch();
			
      bool isNextClientRequest(boost::shared_ptr<BFT::messages::RequestCore>); //inlined
			
      void cpStable(boost::shared_ptr<statemanagement::CheckPointState>);
			
      void setCleanRCQueue(boost::shared_ptr<RequestCoreQueue> _rcq); //inlined
			
      void setCleaner(boost::shared_ptr<Cleaner> _cleaner); //inlined
			
      void setNetwork(boost::shared_ptr<BFT::network::concurrentNet::TCPNetwork> _net);
			
      boost::shared_ptr<BFT::membership::Membership> getMembership(); //inlined 
			
      void start();
					
    protected:
			
      //maintain one copy of the working state
      boost::shared_ptr<statemanagement::CheckPointState> workingState;
      //collection of previous checkpoints
      std::vector<boost::shared_ptr<statemanagement::CheckPointState> > stateSnapshots;
      //index of the most recent stable snapshot
			
      //incoming filtered client requests
      //TODO:uncomment following line after having implemented the filtered requests
      //std::vector<boost::shared_ptr<statemanagement::FilteredQuorum> > filteredQuorums;
			
      //set of certificate liss
      //certificate[i] is requests executed starting from stateSnapshot i
      std::vector< std::vector<boost::shared_ptr< statemanagement::Certificate> > > certificates;
      //index of the certificate list that we are currently working on
      int currentIndex;
      int baseIndex;
      //collection of messages that are in the future
      std::vector<boost::shared_ptr< messages::PrePrepare> > futurePPs;
      std::vector< std::vector<boost::shared_ptr< messages::Prepare> > > futurePs;
      std::vector< std::vector<boost::shared_ptr< messages::Commit> > > futureCs;
			
      uint32_t currentView;
      int32_t maxPrepared; //to be initialized at -1 in constructors
      int32_t maxCommitted; //to be initialized at -1 in constructors									 

      boost::shared_ptr<BFT::messages::Quorum<BFT::messages::CPTokenMessage> > cpCert;
			
      //Cleaner
      boost::shared_ptr<Cleaner> cleaner;
			
      //retransmission backoffs
      std::vector<uint32_t> lastLastExecCheck;
      std::vector<int> lastExecDelay;
      std::vector<bool> lastExecLoadCP;
      std::vector<uint32_t> lastClientRetrans;
      std::vector<uint32_t> lastRidForClient;
			
      //ViewChanges
      bool changingView;  //to be initialized at false
      std::vector<boost::shared_ptr<statemanagement::ViewChangeRow> > viewChanges;
      boost::shared_ptr<statemanagement::ViewInfo> vInfo;
      std::vector<boost::shared_ptr<messages::NewView> > nvCache;
      bool actedOnView; //to be initialized at false;
      bool actedOnDefinedView; // to be initialized as false false;
			
      //NB logging
      //TODO: implement all the NBLogging stuff
      /*
	private final int NUM_LOGGERS = 2;
	private NBLogQueue nbq;
      */
      int currentLog;

      //CPLogging
      //TODO: implement the CP logging stuff
      //TODO: use the threadpool library? [http://threadpool.sourceforge.net/]
			
      //TODO: implement the RequestCoreQueue
			
			
      //   METHODS
			
      void process(boost::shared_ptr<BFT::messages::ClientRequest> _cr);
      //TODO
      //void process(boost::shared_ptr<BFT::order::messages::ForwardedRequest> _fr);
      //void process(boost::shared_ptr<BFT::messages::FilteredRequestCore> _frc);
			
      void process(boost::shared_ptr<BFT::messages::LastExecuted> _le);
			
      void process(boost::shared_ptr<BFT::messages::CPLoaded> _cpl);
			
      void process(boost::shared_ptr<BFT::messages::CPTokenMessage> _cpt);
			
      void process(boost::shared_ptr<BFT::order::messages::PrePrepare> _pp);
			
      void process(boost::shared_ptr<BFT::order::messages::Prepare> _p);
			
      void process(boost::shared_ptr<BFT::order::messages::Commit> _c);
			
      void process(boost::shared_ptr<BFT::order::messages::ViewChange> _vc);

      void process(boost::shared_ptr<BFT::order::messages::NewView> _nv);
			
      void process(boost::shared_ptr<BFT::order::messages::ViewChangeAck> _vca);
						
      void process(boost::shared_ptr<BFT::order::messages::ConfirmView> _cv);

      void process(boost::shared_ptr<BFT::order::messages::StartView> _sv);

      //TODO
      //void process(boost::shared_ptr<BFT::order::messages::MissingViewChange> _mvc);
      //void process(boost::shared_ptr<BFT::order::messages::RelayViewChange> _rvc);
      //void process(boost::shared_ptr<BFT::order::messages::MissingOps> _mo);
      //void process(boost::shared_ptr<BFT::order::messages::RelayOps> _ro);
			
      void process(boost::shared_ptr<BFT::order::messages::MissingCP> _mcp);
			
      void process(boost::shared_ptr<BFT::order::messages::RelayCP> _rcp);
			
      bool tryRetransmit(boost::shared_ptr<BFT::messages::RequestCore> _rc);
			
      void actonCPToken(boost::shared_ptr<BFT::messages::CPTokenMessage>);
			
      void actOnPrepared(uint32_t _seqno);
			
      void actOnCommitted(uint32_t _seqno);
			
      void makeCPStable(boost::shared_ptr<statemanagement::CheckPointState> _cps);
			
      void processClean(boost::shared_ptr<std::vector<boost::shared_ptr<BFT::messages::RequestCore> > > _rcs);
			
      void processClean(boost::shared_ptr<messages::PrePrepare> _pp);
			
      void createNextBatch(boost::shared_ptr<std::vector<boost::shared_ptr<BFT::messages::RequestCore> > > _rcs);
			
      void writeAndSend(boost::shared_ptr<BFT::messages::NextBatch> _nb);
			
      void forwardNextBatches(uint32_t _baseline, uint32_t senderIndex);
			
      void addNextBatch(boost::shared_ptr<BFT::messages::NextBatch> _nb);
						
      int stateIndex(uint32_t _seqNo);
			
      int certificateIndex(uint32_t _seqNo); //inlined
			
      uint32_t getBaseSequenceNumber();//inlined
			
      bool amIPrimary(uint32_t view); //inlined
			
      int primary(uint32_t view); //inlined
			
      boost::shared_ptr<statemanagement::CheckPointState> getWorkingState(); //inlined	

      void newWorkingState();
			
      void garbageCollect(uint32_t _seqno);
			
      void startViewChange(uint32_t _view);
			
      void actOnDefinedView();
			
      void actOnCompleteView();
			
      void actOnConfirmedView();
				
    private:
	

      uint32_t deltaOrdered, previousOrdered, nowTime, previousTime, deltaTime;
      float speed; 
			
      boost::shared_ptr<BFT::messages::CPTokenMessage> cachedCPT;
      boost::shared_ptr<statemanagement::CheckPointState> waitingForCPT;
	
      boost::shared_ptr<BFT::membership::Membership> membership; //read the config file and fill up membership info
      boost::shared_ptr<BFT::BaseNode> baseNode; //base node reference, used to /send/ packets

      boost::shared_ptr<RequestCoreQueue> rcQueue;

      uint32_t CPNOW; //to be initialized at -1 in constructors
      uint32_t requestsOrdered; //to be initialize at 0 in constructors
			
			
      uint32_t vstart;
      uint32_t fileStart;
      uint32_t count; //to be initialized at 0;
      uint32_t filtercount;
      bool procFirstReq; //to be initialized at false
      bool procFirstFiltReq; //to be initialized at false
      uint32_t filtersmall; //to be initialized at 0
      uint32_t filtermed; //to be initialized at 0
      uint32_t filterlarge; //to be initialized at 0
			
      uint32_t nonDetcounter; 
			
      boost::shared_ptr<BFT::network::concurrentNet::TCPNetwork> filterNet;
      boost::shared_ptr<BFT::network::concurrentNet::TCPNetwork> orderNet;
      boost::shared_ptr<BFT::network::concurrentNet::TCPNetwork> execNet;
      boost::shared_ptr<BFT::network::concurrentNet::TCPNetwork> clientNet;
			
			
      struct timespec time;
      uint32_t millisecondTime();
			
    };
		
    inline boost::shared_ptr<statemanagement::CheckPointState> OrderBaseNode::getWorkingState() {return workingState;}
		
    inline uint32_t OrderBaseNode::getCurrentSequenceNumber() {return workingState.get()->getCurrentSequenceNumber();}
		
    inline int OrderBaseNode::certificateIndex(uint32_t _seqNo) {return(int) _seqNo % BFT::order::Parameters::checkPointInterval;}
		
    inline uint32_t OrderBaseNode::getBaseSequenceNumber() {return stateSnapshots.at(baseIndex).get()->getCurrentSequenceNumber();}	
		
    inline bool OrderBaseNode::isNextClientRequest(boost::shared_ptr<BFT::messages::RequestCore> _rc) 
    {return (workingState.get()->getLastOrdered(_rc.get()->getSendingClient()) + 1 ) ==  (_rc.get()->getRequestId());}
		
    inline void OrderBaseNode::setCleanRCQueue(boost::shared_ptr<RequestCoreQueue> _rcq) {rcQueue = _rcq;} //inlined	
		
    inline void OrderBaseNode::setCleaner(boost::shared_ptr<Cleaner> _cleaner) {cleaner = _cleaner;}
		
    inline boost::shared_ptr<BFT::membership::Membership> OrderBaseNode::getMembership() {return membership;}
		
    inline int OrderBaseNode::primary(uint32_t _view) {return _view % BFT::Parameters::getOrderCount() ;}
		
    inline bool OrderBaseNode::amIPrimary(uint32_t _view) {return primary(_view) == baseNode.get()->getMyOrderIndex();}
  }
}

#endif
